﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Rhino.Mocks;
using Chefbook.DataObjects;

namespace UnitTests.DataObjectsTests
{
    [TestFixture]
    public class IngredientFixture
    {
        private MockRepository mocks = new MockRepository();
        private Recipe recipe;
        private Ingredient testIngredient;
        [SetUp]
        public void Init()
        {
            var category = new Category(null);
            recipe = new Recipe(category);
            testIngredient = new Ingredient(recipe);
        }

        [Test]
        public void ConstructorTest()
        {
            Assert.AreEqual("", testIngredient.Name, "Constructor Name test failed");
            Assert.AreEqual("", testIngredient.Units, "Constructor Units test failed");
            Assert.AreEqual(0.0, testIngredient.Amount, "Constructor Amount test failed");
            Assert.AreEqual(recipe, testIngredient.Recipe, "Ingredient's Recipe property didn't point at the containing Recipe");
            Assert.AreEqual(1, recipe.Ingredients.Count((i) => i == testIngredient), "Recipe's ingredients didn't containe exactly one copy of Root");
        }

        [Test]
        public void ReassignRecipeThrowsException()
        {
            var category = new Category(null);
            recipe = new Recipe(category);
            testIngredient = new Ingredient();
            Assert.IsNull(testIngredient.Recipe);
            Assert.False(recipe.Ingredients.Contains(testIngredient));
            testIngredient.AssertPropertyChangedFired(() => testIngredient.Recipe = recipe, "Recipe");
            Assert.IsNotNull(testIngredient.Recipe);
            Assert.True(recipe.Ingredients.Contains(testIngredient));
            Assert.Throws<InvalidOperationException>(() => testIngredient.Recipe = new Recipe(null));

        }

        [Test]
        public void RenameTest()
        {
            testIngredient.AssertPropertyChangedFired(() => testIngredient.Name = "Ground Beef", "Name");
            Assert.AreEqual("Ground Beef", testIngredient.Name, "Rename test failed");
        }

        [Test]
        public void RenameNullTest()
        {
            Assert.Throws<ArgumentNullException>(() => testIngredient.Name = null);
        }

        [Test]
        public void ChangeUnitsTest()
        {
            testIngredient.AssertPropertyChangedFired(() => testIngredient.Units = "Lb", "Units");
            Assert.AreEqual("Lb", testIngredient.Units, "Change Units test failed");
        }

        [Test]
        public void ChangeUnitsNullTest()
        {
            Assert.Throws<ArgumentNullException>(() => testIngredient.Units = null);
        }

        [Test]
        public void ChangeAmountTest()
        {
            testIngredient.AssertPropertyChangedFired(() => testIngredient.Amount = 1, "Amount");
            Assert.AreEqual(1, testIngredient.Amount, "Change Amount test failed");
        }

        [Test]
        public void ChangeAmountNegativeTest()
        {
            Assert.Throws<ArgumentException>(() => testIngredient.Amount = -0.1f);
        }

        [Test]
        public void EqualsTest()
        {
            Ingredient expected = new Ingredient(new Recipe(new Category(null)));
            expected.Units = "Hello";
            expected.Name = "World";
            expected.Amount = 2.84f;

            Ingredient actual = new Ingredient(new Recipe(new Category(null)));
            actual.Units = "Hello";
            actual.Name = "World";
            actual.Amount = 2.84f;

            Assert.True(expected.ValueEquals(actual));
        }

        [Test]
        public void NotEqualsTest1()
        {
            Ingredient expected = new Ingredient(new Recipe(new Category(null)));
            expected.Units = "Hello";
            expected.Name = "World";
            expected.Amount = 2.8f;

            Ingredient actual = new Ingredient(new Recipe(new Category(null)));
            actual.Units = "Hello";
            actual.Name = "World";
            actual.Amount = 2.84f;

            Assert.False(expected.ValueEquals(actual));
        }

        [Test]
        public void NotEqualsTest2()
        {
            Ingredient expected = new Ingredient(new Recipe(new Category(null)));
            expected.Units = "Hi";
            expected.Name = "World";
            expected.Amount = 2.8f;

            Ingredient actual = new Ingredient(new Recipe(new Category(null)));
            actual.Units = "Hello";
            actual.Name = "World";
            actual.Amount = 2.84f;

            Assert.False(expected.ValueEquals(actual));
        }

        [Test]
        public void ToStringTest1()
        {
            testIngredient.Amount = 2f;
            testIngredient.Units = "tsp";
            testIngredient.Name = "salt";
            Assert.AreEqual("2 tsp salt", testIngredient.ToString());
        }

        [Test]
        public void ToStringTest2()
        {
            testIngredient.Amount = 2f;
            testIngredient.Units = "";
            testIngredient.Name = "apples";
            Assert.AreEqual("2 apples", testIngredient.ToString());
        }

        [Test]
        public void ToStringTest3()
        {
            testIngredient.Amount = 0;
            testIngredient.Units = "tsp";
            testIngredient.Name = "pepper";
            Assert.AreEqual("Pepper to taste", testIngredient.ToString());
        }
    }
}
